/* Copyright 2007-2008 dnAnalytics Project.
 *
 * Contributors to this file:
 * Patrick van der Velde
 *
 * This file is part of dnAnalytics.  dnAnalytics is licensed under the 
 * Microsoft Public License. See License.txt for a complete copy of the
 * license.
 */

using System;
using System.Diagnostics;
using dnAnalytics.LinearAlgebra;
using dnAnalytics.LinearAlgebra.Solvers;
using NUnit.Framework;

namespace dnAnalytics.Tests.LinearAlgebra.Solvers
{
    [TestFixture]
    public sealed class FailureStopCriteriumTest
    {
        [Test]
        public void Create()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "Should have a criterium now");
        }
        
        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void DetermineStatusWithIllegalIterationNumber()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            criterium.DetermineStatus(-1, new DenseVector(3, 4), new DenseVector(3, 5), new DenseVector(3, 6));
            Assert.Fail();
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DetermineStatusWithNullSolutionVector()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            criterium.DetermineStatus(1, null, new DenseVector(3, 6), new DenseVector(4, 4));
            Assert.Fail();
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DetermineStatusWithNullResidualVector()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            criterium.DetermineStatus(1, new DenseVector(3, 4), new DenseVector(3, 6), null);
            Assert.Fail();
        }

        [Test]
        [ExpectedException(typeof(NotConformableException))]
        public void DetermineStatusWithNonMatchingVectors()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            criterium.DetermineStatus(1, new DenseVector(3, 4), new DenseVector(3, 6), new DenseVector(4, 4));
            Assert.Fail();
        }

        [Test]
        public void DetermineStatusWithResidualNaN()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            DenseVector solution = new DenseVector(new double[] { 1, 1, 2 });
            DenseVector source = new DenseVector(new double[] { 1001, 0, 2003 });
            DenseVector residual = new DenseVector(new double[] { 1000, double.NaN, 2001 });

            criterium.DetermineStatus(5, solution, source, residual);
            Assert.IsInstanceOfType(typeof(CalculationFailure), criterium.Status, "Should be failed");
        }

        [Test]
        public void DetermineStatusWithSolutionNaN()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            DenseVector solution = new DenseVector(new double[] { 1, 1, double.NaN });
            DenseVector source = new DenseVector(new double[] { 1001, 0, 2003 });
            DenseVector residual = new DenseVector(new double[] { 1000, 1000, 2001 });

            criterium.DetermineStatus(5, solution, source, residual);
            Assert.IsInstanceOfType(typeof(CalculationFailure), criterium.Status, "Should be failed");
        }

        [Test]
        public void DetermineStatus()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            DenseVector solution = new DenseVector(new double[] { 3, 2, 1 });
            DenseVector source = new DenseVector(new double[] { 1001, 0, 2003 });
            DenseVector residual = new DenseVector(new double[] { 1, 2, 3 });

            criterium.DetermineStatus(5, solution, source, residual);
            Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running");
        }

        [Test]
        public void ResetCalculationState()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            DenseVector solution = new DenseVector(new double[] { 1, 1, 2 });
            DenseVector source = new DenseVector(new double[] { 1001, 0, 2003 });
            DenseVector residual = new DenseVector(new double[] { 1000, 1000, 2001 });

            criterium.DetermineStatus(5, solution, source, residual);
            Assert.IsInstanceOfType(typeof(CalculationRunning), criterium.Status, "Should be running");

            criterium.ResetToPrecalculationState();
            Assert.IsInstanceOfType(typeof(CalculationIndetermined), criterium.Status, "Should not have started");
        }

        [Test]
        public void Clone()
        {
            FailureStopCriterium criterium = new FailureStopCriterium();
            Assert.IsNotNull(criterium, "There should be a criterium");

            IIterationStopCriterium clone = criterium.Clone();
            Assert.IsInstanceOfType(typeof(FailureStopCriterium), clone, "Wrong criterium type");
        }
    }
}
